//
// Templet.h
//
// $Id: //base/include/Templet.h
//
// Library: base
// Package: base
// Module : Templet
// Author :	Jelin,doitsjz@163.com
// Date	  :	10/30/2012
// 
// Definition of the Templet class.
//
// Copyright (c) 2012-2012, iGuard.
//

#include "RTSPResponse.h"
#include "poco/DateTime.h"
#include "poco/NumberFormatter.h"
#include "poco/NumberParser.h"
#include "poco/DateTimeFormatter.h"
#include "poco/DateTimeFormat.h"
#include "poco/DateTimeParser.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/NameValueCollection.h"

using Poco::DateTime;
using Poco::NumberFormatter;
using Poco::NumberParser;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
using Poco::DateTimeParser;

using Poco::Net::NotAuthenticatedException;
using Poco::Net::MessageException;
using Poco::Net::NoMessageException;

const std::string RTSPResponse::RTSP_REASON_CONTINUE                        = "Continue";
const std::string RTSPResponse::RTSP_REASON_SWITCHING_PROTOCOLS             = "Switching Protocols";
const std::string RTSPResponse::RTSP_REASON_OK                              = "OK";
const std::string RTSPResponse::RTSP_REASON_CREATED                         = "Created";
const std::string RTSPResponse::RTSP_REASON_ACCEPTED                        = "Accepted";
const std::string RTSPResponse::RTSP_REASON_NONAUTHORITATIVE                = "Non-Authoritative Information";
const std::string RTSPResponse::RTSP_REASON_NO_CONTENT                      = "No Content";
const std::string RTSPResponse::RTSP_REASON_RESET_CONTENT                   = "Reset Content";
const std::string RTSPResponse::RTSP_REASON_PARTIAL_CONTENT                 = "Partial Content";
const std::string RTSPResponse::RTSP_REASON_MULTIPLE_CHOICES                = "Multiple Choices";
const std::string RTSPResponse::RTSP_REASON_MOVED_PERMANENTLY               = "Moved Permanently";
const std::string RTSPResponse::RTSP_REASON_FOUND                           = "Found";
const std::string RTSPResponse::RTSP_REASON_SEE_OTHER                       = "See Other";
const std::string RTSPResponse::RTSP_REASON_NOT_MODIFIED                    = "Not Modified";
const std::string RTSPResponse::RTSP_REASON_USEPROXY                        = "Use Proxy";
const std::string RTSPResponse::RTSP_REASON_TEMPORARY_REDIRECT              = "Temporary Redirect";
const std::string RTSPResponse::RTSP_REASON_BAD_REQUEST                     = "Bad Request";
const std::string RTSPResponse::RTSP_REASON_UNAUTHORIZED                    = "Unauthorized";
const std::string RTSPResponse::RTSP_REASON_PAYMENT_REQUIRED                = "Payment Required";
const std::string RTSPResponse::RTSP_REASON_FORBIDDEN                       = "Forbidden";
const std::string RTSPResponse::RTSP_REASON_NOT_FOUND                       = "Not Found";
const std::string RTSPResponse::RTSP_REASON_METHOD_NOT_ALLOWED              = "Method Not Allowed";
const std::string RTSPResponse::RTSP_REASON_NOT_ACCEPTABLE                  = "Not Acceptable";
const std::string RTSPResponse::RTSP_REASON_PROXY_AUTHENTICATION_REQUIRED   = "Proxy Authentication Required";
const std::string RTSPResponse::RTSP_REASON_REQUEST_TIMEOUT                 = "Request Time-out";
const std::string RTSPResponse::RTSP_REASON_CONFLICT                        = "Conflict";
const std::string RTSPResponse::RTSP_REASON_GONE                            = "Gone";
const std::string RTSPResponse::RTSP_REASON_LENGTH_REQUIRED                 = "Length Required";
const std::string RTSPResponse::RTSP_REASON_PRECONDITION_FAILED             = "Precondition Failed";
const std::string RTSPResponse::RTSP_REASON_REQUESTENTITYTOOLARGE           = "Request Entity Too Large";
const std::string RTSPResponse::RTSP_REASON_REQUESTURITOOLONG               = "Request-URI Too Large";
const std::string RTSPResponse::RTSP_REASON_UNSUPPORTEDMEDIATYPE            = "Unsupported Media Type";
const std::string RTSPResponse::RTSP_REASON_REQUESTED_RANGE_NOT_SATISFIABLE = "Requested Range Not Satisfiable";
const std::string RTSPResponse::RTSP_REASON_EXPECTATION_FAILED              = "Expectation Failed";
const std::string RTSPResponse::RTSP_REASON_INTERNAL_SERVER_ERROR           = "Internal Server Error";
const std::string RTSPResponse::RTSP_REASON_NOT_IMPLEMENTED                 = "Not Implemented";
const std::string RTSPResponse::RTSP_REASON_BAD_GATEWAY                     = "Bad Gateway";
const std::string RTSPResponse::RTSP_REASON_SERVICE_UNAVAILABLE             = "Service Unavailable";
const std::string RTSPResponse::RTSP_REASON_GATEWAY_TIMEOUT                 = "Gateway Time-out";
const std::string RTSPResponse::RTSP_REASON_VERSION_NOT_SUPPORTED           = "RTSP Version not supported";
const std::string RTSPResponse::RTSP_REASON_UNKNOWN                         = "???";
const std::string RTSPResponse::DATE       = "Date";
const std::string RTSPResponse::SET_COOKIE = "Set-Cookie";


RTSPResponse::RTSPResponse():
	_status(RTSP_OK),
	_reason(getReasonForStatus(RTSP_OK))
{
}

	
RTSPResponse::RTSPResponse(RTSPStatus status, const std::string& reason):
	_status(status),
	_reason(reason)
{
}


	
RTSPResponse::RTSPResponse(const std::string& version, RTSPStatus status, const std::string& reason):
	RTSPMessage(version),
	_status(status),
	_reason(reason)
{
}

	
RTSPResponse::RTSPResponse(RTSPStatus status):
	_status(status),
	_reason(getReasonForStatus(status))
{
}


RTSPResponse::RTSPResponse(const std::string& version, RTSPStatus status):
	RTSPMessage(version),
	_status(status),
	_reason(getReasonForStatus(status))
{
}


RTSPResponse::~RTSPResponse()
{
}


void RTSPResponse::setStatus(RTSPStatus status)
{
	_status = status;
}


void RTSPResponse::setStatus(const std::string& status)
{
	setStatus((RTSPStatus) NumberParser::parse(status));
}
	
	
void RTSPResponse::setReason(const std::string& reason)
{
	_reason = reason;
}


void RTSPResponse::setStatusAndReason(RTSPStatus status, const std::string& reason)
{
	_status = status;
	_reason = reason;
}

	
void RTSPResponse::setStatusAndReason(RTSPStatus status)
{
	setStatusAndReason(status, getReasonForStatus(status));
}

void RTSPResponse::setPublic(const std::string& pub)
{
	if (pub.empty())
		setPublic();
	else	
		set(Public,pub);
}

void RTSPResponse::setPublic()
{
	std::string tmp="DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE";
	set(Public,tmp);
}
const std::string& RTSPResponse::getPublic() const
{
	std::string tmp="DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE";
	return get(Public,tmp);
}
void RTSPResponse::write(std::ostream& ostr) const
{
	ostr << getVersion() << " " << static_cast<int>(_status) << " " << _reason << "\r\n";
	RTSPMessage::write(ostr);
	ostr << "\r\n";
	if (!_body.empty())
		ostr << _body;// << "\r\n";
}

void RTSPResponse::read(std::istream& istr)
{
	static const int eof = std::char_traits<char>::eof();

	std::string version;
	std::string status;
	std::string reason;
	
	int ch =  istr.get();
	if (ch == eof) throw NoMessageException();
	while (Poco::Ascii::isSpace(ch)) ch = istr.get();
	if (ch == eof) throw MessageException("No RTSP response header");
	while (!Poco::Ascii::isSpace(ch) && ch != eof && version.length() < MAX_VERSION_LENGTH) { version += (char) ch; ch = istr.get(); }
	if (!Poco::Ascii::isSpace(ch)) throw MessageException("Invalid RTSP version string");
	while (Poco::Ascii::isSpace(ch)) ch = istr.get();
	while (!Poco::Ascii::isSpace(ch) && ch != eof && status.length() < MAX_STATUS_LENGTH) { status += (char) ch; ch = istr.get(); }
	if (!Poco::Ascii::isSpace(ch)) throw MessageException("Invalid RTSP status code");
	while (Poco::Ascii::isSpace(ch)) ch = istr.get();
	while (ch != '\r' && ch != '\n' && ch != eof && reason.length() < MAX_REASON_LENGTH) { reason += (char) ch; ch = istr.get(); }
	if (!Poco::Ascii::isSpace(ch)) throw MessageException("RTSP reason string too long");
	if (ch == '\r') ch = istr.get();

	RTSPMessage::read(istr);
	ch = istr.get();
	while (ch != '\n' && ch != eof) { ch = istr.get(); }
	ch = istr.get();
	while (ch != eof) { _body += (char) ch;ch = istr.get(); }

	setVersion(version);
	setStatus(status);
	setReason(reason);
}


const std::string& RTSPResponse::getReasonForStatus(RTSPStatus status)
{
	switch (status)
	{
	case RTSP_CONTINUE: 
		return RTSP_REASON_CONTINUE;
	case RTSP_SWITCHING_PROTOCOLS: 
		return RTSP_REASON_SWITCHING_PROTOCOLS;
	case RTSP_OK: 
		return RTSP_REASON_OK;
	case RTSP_CREATED: 
		return RTSP_REASON_CREATED;
	case RTSP_ACCEPTED: 
		return RTSP_REASON_ACCEPTED;
	case RTSP_NONAUTHORITATIVE:	
		return RTSP_REASON_NONAUTHORITATIVE;
	case RTSP_NO_CONTENT: 
		return RTSP_REASON_NO_CONTENT;
	case RTSP_RESET_CONTENT: 
		return RTSP_REASON_RESET_CONTENT;
	case RTSP_PARTIAL_CONTENT: 
		return RTSP_REASON_PARTIAL_CONTENT;
	case RTSP_MULTIPLE_CHOICES: 
		return RTSP_REASON_MULTIPLE_CHOICES;
	case RTSP_MOVED_PERMANENTLY: 
		return RTSP_REASON_MOVED_PERMANENTLY;
	case RTSP_FOUND: 
		return RTSP_REASON_FOUND;
	case RTSP_SEE_OTHER: 
		return RTSP_REASON_SEE_OTHER;
	case RTSP_NOT_MODIFIED: 
		return RTSP_REASON_NOT_MODIFIED;
	case RTSP_USEPROXY: 
		return RTSP_REASON_USEPROXY;
	case RTSP_TEMPORARY_REDIRECT: 
		return RTSP_REASON_TEMPORARY_REDIRECT;
	case RTSP_BAD_REQUEST: 
		return RTSP_REASON_BAD_REQUEST;
	case RTSP_UNAUTHORIZED: 
		return RTSP_REASON_UNAUTHORIZED;
	case RTSP_PAYMENT_REQUIRED: 
		return RTSP_REASON_PAYMENT_REQUIRED;
	case RTSP_FORBIDDEN: 
		return RTSP_REASON_FORBIDDEN;
	case RTSP_NOT_FOUND: 
		return RTSP_REASON_NOT_FOUND;
	case RTSP_METHOD_NOT_ALLOWED:
		return RTSP_REASON_METHOD_NOT_ALLOWED;
	case RTSP_NOT_ACCEPTABLE: 
		return RTSP_REASON_NOT_ACCEPTABLE;
	case RTSP_PROXY_AUTHENTICATION_REQUIRED: 
		return RTSP_REASON_PROXY_AUTHENTICATION_REQUIRED;
	case RTSP_REQUEST_TIMEOUT: 
		return RTSP_REASON_REQUEST_TIMEOUT;
	case RTSP_CONFLICT: 
		return RTSP_REASON_CONFLICT;
	case RTSP_GONE: 
		return RTSP_REASON_GONE;
	case RTSP_LENGTH_REQUIRED: 
		return RTSP_REASON_LENGTH_REQUIRED;
	case RTSP_PRECONDITION_FAILED: 
		return RTSP_REASON_PRECONDITION_FAILED;
	case RTSP_REQUESTENTITYTOOLARGE: 
		return RTSP_REASON_REQUESTENTITYTOOLARGE;
	case RTSP_REQUESTURITOOLONG: 
		return RTSP_REASON_REQUESTURITOOLONG;
	case RTSP_UNSUPPORTEDMEDIATYPE: 
		return RTSP_REASON_UNSUPPORTEDMEDIATYPE;
	case RTSP_REQUESTED_RANGE_NOT_SATISFIABLE: 
		return RTSP_REASON_REQUESTED_RANGE_NOT_SATISFIABLE;
	case RTSP_EXPECTATION_FAILED: 
		return RTSP_REASON_EXPECTATION_FAILED;
	case RTSP_INTERNAL_SERVER_ERROR: 
		return RTSP_REASON_INTERNAL_SERVER_ERROR;
	case RTSP_NOT_IMPLEMENTED: 
		return RTSP_REASON_NOT_IMPLEMENTED;
	case RTSP_BAD_GATEWAY: 
		return RTSP_REASON_BAD_GATEWAY;
	case RTSP_SERVICE_UNAVAILABLE:
		return RTSP_REASON_SERVICE_UNAVAILABLE;
	case RTSP_GATEWAY_TIMEOUT: 
		return RTSP_REASON_GATEWAY_TIMEOUT;
	case RTSP_VERSION_NOT_SUPPORTED: 
		return RTSP_REASON_VERSION_NOT_SUPPORTED;
	default: 
		return RTSP_REASON_UNKNOWN;
	}
}
void RTSPResponse::clear()
{
	_reason.clear();
	_body.clear();

	NameValueCollection::clear();
}
